//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace Microsoft.Research.DataLayer
{
    /// <summary>
    /// Base interface for the system security policy
    /// </summary>
    public interface ISystemSecurityPolicy
    {
    }

    /// <summary>
    /// Base interface for system permissions
    /// </summary>
    public interface IPermission
    {
        /// <summary>
        /// Display Text to be shown in the UI.
        /// </summary>
        string DisplayName { get; }
        
        /// <summary>
        /// The privileges corresponding to this permission.
        /// </summary>
        IPrivilege[] Privileges { get; }
        
        /// <summary>
        /// Checks if permission is held by the security principal
        /// </summary>
        /// <returns></returns>
        /// <param name="principal"></param>
        bool Check(ISecurityPrincipal principal);

        /// <summary>
        /// Throws an exception if permission is not held by the principal
        /// </summary>
        /// <param name="principal"></param>
        void Ensure(ISecurityPrincipal principal);        
    }

    /// <summary>
    /// Base interface for system privileges
    /// </summary>
    public interface IPrivilege
    {

        /// <summary>
        /// Display Text to be shown in the UI.
        /// </summary>
        string DisplayName { get; }
        
        /// <summary>
        /// Permission that this privilege belongs to
        /// </summary>
        IPermission Permission { get; }

        /// <summary>
        /// Checks if permission is held by the security principal
        /// </summary>
        /// <returns></returns>
        /// <param name="principal"></param>
        bool Check(ISecurityPrincipal principal);

        /// <summary>
        /// Throws an exception if permission is not held by the principal
        /// </summary>
        /// <param name="principal"></param>
        void Ensure(ISecurityPrincipal principal);

    }

    /// <summary>
    /// Denotes a privilege held by a Principal
    /// </summary>
    public class SecurityPermission
    {
        /// <summary>
        /// Object that hold the permission
        /// </summary>
        public ISecurityPrincipal Principal;

        /// <summary>
        /// Privilege held
        /// </summary>
        public IPrivilege Privilege;
    }

    /// <summary>
    /// Objects that implement this interface have support to security and capable of managing permissions
    /// granted and denied to security principals
    /// </summary>
    public interface ISecurableObject
    {
        /// <summary>
        /// Owner of the object
        /// </summary>
        ISecurityPrincipal Owner { get; set; }
    }

    /// <summary>
    /// Internal implementation used by Data Modules, such as permission management dialog
    /// </summary>
    public interface ISecurableObjectInternal : ISecurableObject
    {
        /// <summary>
        /// Returns all the permissions defined for the object
        /// </summary>
        IPermission[] Permission { get; }

        /// <summary>
        /// Set an access right to the object DACL
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="privilege"></param>
        void AddAccess(ISecurityPrincipal principal, IPrivilege privilege);

        /// <summary>
        /// Remove the access right from the object DACL
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="privilege"></param>
        void RemoveAccess(ISecurityPrincipal principal, IPrivilege privilege);

        /// <summary>
        /// Check if object DACL has the right
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="privilege"></param>
        /// <returns></returns>
        bool CheckAccess(ISecurityPrincipal principal, IPrivilege privilege);

        /// <summary>
        /// Fetch the ACL objects.
        /// </summary>
        SecurityPermission[] DACL { get; }
    }

    /// <summary>
    /// This interface is used to fetch and modity security credentials for a given principal
    /// </summary>
    public interface ISecurityCredentialCollection : ICollection<ISecurityCredential>
    {
    }    

    /// <summary>
    /// Defines a security principal (object that can have permissions or privileges to other objects)
    /// </summary>
    public interface ISecurityPrincipal
    {
        /// <summary>
        /// Retrieves and manages the credentials associated with the security principal
        /// </summary>
        ISecurityCredentialCollection Credentials { get; }
    }

   

    /// <summary>
    /// Defines the type of credential to be associated with the security principal
    /// </summary>
    /// <remarks>CredentialType is key to find the correct credential provider to validate the credential</remarks>
    public enum CredentialType
    {
        /// <summary>
        /// Windows SAM authentication
        /// </summary>
        Windows,

        /// <summary>
        /// X.509 certificate
        /// </summary>
        X509Certificate,

        /// <summary>
        /// .NET Live Passport
        /// </summary>
        Passport,

        /// <summary>
        /// Other credential type
        /// </summary>
        Unknown,
    }

    /// <summary>
    /// A security principal has 1+ credentials associated with it. This interface defines the credential
    /// </summary>
    public interface ISecurityCredential
    {
        /// <summary>
        /// Type of credential
        /// </summary>
        CredentialType Type { get; set; }

        /// <summary>
        /// Credential information (format varies based on type)
        /// </summary>
        string Credential { get; set; }
    }
    

    /// <summary>
    /// Possible roles a principal can have in the storage
    /// </summary>
    public enum StorageRole
    {
        /// <summary>
        /// Security principal is storage administrator
        /// </summary>
        Administrator,

        /// <summary>
        /// Security principal is storage user
        /// </summary>
        User,

        /// <summary>
        /// Security principal has 'service' privileges
        /// </summary>
        Service,
    }

    /// <summary>
    /// This is the interface to managing the security of the storage provider. Each provider will implement its own security
    /// based on the principals and roles.
    /// </summary>
    /// <remarks>
    /// If connection provider does not support any security it should throw NotSupportedException exceptions if called
    /// </remarks>
    public interface IStorageSecurity
    {
        /// <summary>
        /// System policy objects should be initialized by Storage.Init() method
        /// </summary>
        ISystemSecurityPolicy SystemPolicy { get; }

        /// <summary>
        /// Grants access to the principal to the storage
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="role"></param>
        void GrantDirectAccess(ISecurityPrincipal principal, StorageRole role);

        /// <summary>
        /// Revoke security principal role access from the storage
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="role"></param>
        void RevokeDirectAccess(ISecurityPrincipal principal, StorageRole role);

        /// <summary>
        /// Checks if the security principal has a specific role permission
        /// </summary>
        /// <param name="principal"></param>
        /// <param name="role"></param>
        /// <returns></returns>
        bool CheckDirectAccess(ISecurityPrincipal principal, StorageRole role);

        /// <summary>
        /// Returns all permissions of the security principal to the store
        /// </summary>
        /// <param name="principal"></param>
        /// <returns></returns>
        StorageRole[] Get(ISecurityPrincipal principal);

        /// <summary>
        /// Returns all permissions granted to the store
        /// </summary>
        /// <returns></returns>
        Dictionary<ISecurityPrincipal, StorageRole[]> Permissions { get; }
    }
}

